﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyEmulators2
{
    internal partial class Conf_DBImporter : ContentPanel
    {
        Importer importer = null;
        BindingSource importerBindingSource = null;

        public Conf_DBImporter()
        {
            InitializeComponent();

            setupToolTip();
            
            importGridView.SelectionChanged += new EventHandler(importGridView_SelectionChanged);
            //called when config closed, stop importer threads here
            //this.HandleDestroyed += new EventHandler(Conf_DBImporter_HandleDestroyed);

            progressLabel.Text = "";

            importerBindingSource = new BindingSource();
            importerBindingSource.AllowNew = true;
            importerBindingSource.DataSource = typeof(MyEmulators2.RomMatch);

            //setup import grid
            importGridView.AutoGenerateColumns = false;
            importGridView.DataSource = importerBindingSource;

            importer = Conf_GlobalSettings.Instance.Importer;

            //add progress events
            importer.Progress += new ImportProgressHandler(importer_Progress);
            importer.RomStatusChanged += new RomStatusChangedHandler(importer_RomStatusChanged);
        }

        void importGridView_SelectionChanged(object sender, EventArgs e)
        {
            updateButtons();
        }

        void updateButtons()
        {
            if (importGridView.SelectedRows.Count == 0)
                return;
            else if (importGridView.SelectedRows.Count > 1)
            {
                approveButton.Enabled = true;
                findButton.Enabled = false;
                ignoreButton.Enabled = true;
                return;
            }

            findButton.Enabled = true;

            RomMatch match = importGridView.SelectedRows[0].DataBoundItem as RomMatch;

            //Allow approve only if match has been checked and not ignored or already commited
            if (match.InfoChecked && !match.Ignore && importGridView.SelectedRows[0].Cells[columnTitle.Name].Value != null)
            {
                approveButton.Enabled = true;
            }
            else
            {
                approveButton.Enabled = false;
            }

            //too late to ignore if already commited
            if (match.Commited || match.Ignore)
            {
                ignoreButton.Enabled = false;
            }
            else
            {
                ignoreButton.Enabled = true;
            }


            //Allow import start only if importer is ready and not already started
            if (importGridView.Rows.Count > 0 && importer.Ready)
            {
                startButton.Enabled = true;
            }
            else
            {
                startButton.Enabled = false;
            }
        }

        void Conf_DBImporter_HandleDestroyed(object sender, EventArgs e)
        {
            if (importer != null)
                importer.Stop(); //close all background threads
        }

        void importer_Progress(int percentDone, int taskCount, int taskTotal, string taskDescription)
        {
            if (InvokeRequired)
            {
                //Make sure we only execute on main thread
                BeginInvoke(new MethodInvoker(delegate()
                {
                    importer_Progress(percentDone, taskCount, taskTotal, taskDescription);
                }
                    ));
                return;
            }

            progressBar.Value = percentDone;
            progressLabel.Text = string.Format("{0}/{1} - {2}", taskCount, taskTotal, taskDescription);

            //if there's nothing to do hide progress info
            if (taskCount == 0 && taskTotal == 0 && percentDone == 100)
            {
                progressBar.Visible = false;
                progressLabel.Visible = false;
            }
            //else ensure progress info is visible
            else
            {
                progressBar.Visible = true;
                progressLabel.Visible = true;
            }

        }

        void importer_RomStatusChanged(object obj, ImportAction action)
        {
            if (InvokeRequired)
            {
                //Make sure we only execute on main thread
                BeginInvoke(new MethodInvoker(delegate()
                {
                    importer_RomStatusChanged(obj, action);
                }
                ));
                return;
            }

            int rowNum = -1;
            Image statusIcon = new Bitmap(1, 1);
            string statusTxt = "";

            switch (action)
            {
                case ImportAction.ImportWaiting:
                case ImportAction.ImportFinished:
                    return;
                //occurs after DB refresh on importer load, add all files to grid
                case ImportAction.PendingFilesAdded:
                    importerBindingSource.Clear(); //remove any leftovers
                    addRow(obj as List<RomMatch>);
                    return;
                //Occurs after a match is manually added whilst importer running, check if file already in grid (Ignored) or add
                case ImportAction.PendingFileAdded:
                    checkRow(obj as RomMatch);
                    return;
                case ImportAction.NoFilesFound:
                    importerBindingSource.Clear();
                    importer_Progress(0, 0, 0, "No new files to import");
                    return;
                //set info
                case ImportAction.MatchReprocessed: //reset match status
                    statusTxt = "";
                    statusIcon = MyEmulators2.Properties.Resources.information;
                    break;
                case ImportAction.MatchNeedsInput: //user input requested
                    statusTxt = "needs input";
                    statusIcon = MyEmulators2.Properties.Resources.information;
                    break;
                case ImportAction.MatchApproved: //match user/auto approved
                    statusTxt = "approved";
                    statusIcon = MyEmulators2.Properties.Resources.approved;
                    break;
                case ImportAction.MatchCommited: //Game updated and commited
                    statusTxt = "commited";
                    statusIcon = MyEmulators2.Properties.Resources.accept;
                    break;
                case ImportAction.MatchIgnored: //Match removed from importer and ignored
                    statusTxt = "ignored";
                    statusIcon = MyEmulators2.Properties.Resources.ignored;
                    break;
                case ImportAction.MatchRemoved:
                    importerBindingSource.Remove(obj);
                    return;
                default:
                    return;
            }

            rowNum = importerBindingSource.IndexOf(obj);
            if (rowNum == -1) //match not in grid
                return;

            //set status icon
            importGridView.Rows[rowNum].Cells[columnIcon.Name].Value = statusIcon;
            importGridView.Rows[rowNum].Cells[columnDebug.Name].Value = statusTxt;

            //setup ComboBox cell with possible matches
            DataGridViewComboBoxCell comboBox = (DataGridViewComboBoxCell)importGridView.Rows[rowNum].Cells[columnTitle.Name]; //get the ComboBox cell
            comboBox.DisplayMember = "DisplayMember";
            comboBox.ValueMember = "Self";
            comboBox.Value = null;
            comboBox.Items.Clear(); //remove any leftovers

            RomMatch romMatch = (RomMatch)obj;
            bool check = romMatch.GameDetails != null;

            foreach (ScraperResult details in romMatch.PossibleGameDetails)
            {
                int index = comboBox.Items.Add(details); //possible matches

                if (check && romMatch.GameDetails.SiteId == details.SiteId)
                    comboBox.Value = comboBox.Items[index];
            }

            if (!check && comboBox.Items.Count > 0)
                comboBox.Value = comboBox.Items[0]; //select first value

            updateButtons();
        }

        //adds a List of RomMatches to the BindingSource/Grid
        void addRow(List<RomMatch> romMatches)
        {
            if (romMatches == null)
                return;

            for (int x = 0; x < romMatches.Count; x++)
            {
                addRow(romMatches[x]);
            }
        }

        void addRow(RomMatch romMatch)
        {
            int rowNum = importerBindingSource.Add(romMatch);
            if (rowNum == 0 && importGridView.Rows.Count > 0)
                importGridView.Rows[0].Selected = true; //if first item select it

        }

        //checks if a RomMatch with the same ID is already in the BindingSource, if so it's status is reset else it's added
        void checkRow(RomMatch romMatch)
        {
            foreach (DataGridViewRow row in importGridView.Rows)
            {
                //Game already in gridview, must be previously ignored. Reset status and return
                if (romMatch.ID == ((RomMatch)row.DataBoundItem).ID)
                {
                    int rowNum = row.Index;
                    importerBindingSource.RemoveAt(rowNum);
                    importerBindingSource.Insert(rowNum, romMatch);
                    importer_RomStatusChanged(romMatch, ImportAction.MatchReprocessed);
                    return;
                }
            }

            //if we've reached this far then game not in gridview so add
            addRow(romMatch);
        }

        private void Conf_DBImporter_Load(object sender, EventArgs e)
        {
        }

        public override void update()
        {
            if (!importer.Started)
            {
                importer.Restart();
            }
            base.update();
        }

        public override void close()
        {
            new System.Threading.Thread(new System.Threading.ThreadStart(delegate()
                {
                    if (importer != null)
                        importer.Stop(); //close all background threads
                }
            )).Start();
            base.close();
        }

        //Approve selected match
        void approveButton_Click(object sender, EventArgs e)
        {
            importGridView.EndEdit();
            if (importGridView.SelectedRows.Count < 1)
                return;

            List<RomMatch> matches = new List<RomMatch>();

            foreach (DataGridViewRow row in importGridView.SelectedRows)
            {
                RomMatch romMatch = row.DataBoundItem as RomMatch;
                if (romMatch == null)
                    continue;

                if (!romMatch.InfoChecked || romMatch.Ignore || row.Cells[columnTitle.Name].Value == null)
                    continue;

                romMatch.GameDetails = ((DataGridViewComboBoxCell)row.Cells[columnTitle.Name]).Value as ScraperResult;
                matches.Add(romMatch);
            }

            if (matches.Count == 0)
                return;
            else if (matches.Count == 1)
                importer.Approve(matches[0]);
            else
            {
                Conf_ProgressDialog dlg = new Conf_ProgressDialog(matches.ToArray(), new ProgressDialogDelegate(delegate(object o)
                    {
                        RomMatch match = (RomMatch)o;
                        importer.Approve(match);
                        return "Approving " + match.Title;
                    }
                    ));
                dlg.ShowDialog();
                dlg.Dispose();
            }

            updateButtons();
        }

        //Manual search
        private void findButton_Click(object sender, EventArgs e)
        {
            if (importGridView.SelectedRows.Count == 0)
                return;

            RomMatch match = importGridView.SelectedRows[0].DataBoundItem as RomMatch;
            Conf_ManualSearch searchDlg = new Conf_ManualSearch(match.Title);
            if (searchDlg.ShowDialog() == DialogResult.OK)
            {
                match.Title = searchDlg.searchTerm;
                ((DataGridViewComboBoxCell)importGridView.SelectedRows[0].Cells[columnTitle.Name]).Items.Clear();
                importer.ReProcess(match);
            }
            updateButtons();
        }

        void ignoreButton_Click(object sender, EventArgs e)
        {
            if (importGridView.SelectedRows.Count < 1)
                return;

            List<RomMatch> matches = new List<RomMatch>();
            foreach (DataGridViewRow row in importGridView.SelectedRows)
            {
                RomMatch match = row.DataBoundItem as RomMatch;
                if (match == null || match.Commited || match.Ignore)
                    continue;
                matches.Add(match);
            }

            if (matches.Count == 0)
                return;
            else if (matches.Count == 1)
                importer.Ignore(matches[0]);
            else
            {
                Conf_ProgressDialog dlg = new Conf_ProgressDialog(matches.ToArray(), new ProgressDialogDelegate(delegate(object o)
                    {
                        RomMatch match = (RomMatch)o;
                        importer.Ignore(match);
                        return "Ignoring " + match.Title;
                    }
                    ));
                dlg.ShowDialog();
                dlg.Dispose();
            }

            updateButtons();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            if (importer == null || !importer.Ready)                
                return;

            if (importer.Started)
            {
                startButton.Enabled = false;
                startButton.Text = "Start";
                importer.Restart();
            }
            else
            {
                importer.StartRetrieving();
                startButton.Text = "Stop";
            }
        }

        internal void Stop()
        {
            if (importer != null)
                importer.Stop();
        }

        #region ToolTip

        void setupToolTip()
        {
            importToolTip.SetToolTip(approveButton, "Approve selected item");
            importToolTip.SetToolTip(findButton, "Manual search");
            importToolTip.SetToolTip(ignoreButton, "Ignore selected item");
        }

        #endregion

    }
}
